package xcmg.device.web.threeGuaranteesPur;

import com.github.pagehelper.PageInfo;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import xcmg.device.dao.entity.company.CompanyDealerDO;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesOutDO;
import xcmg.device.dao.entity.threeGuaranteesPur.ThreeGuaranteesPurDO;
import xcmg.device.dao.entity.warehouse.WarehouseDO;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.infra.AuthCode;
import xcmg.device.infra.BasicController;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.JsonUtil;
import xcmg.device.infra.annotation.ExternalApiRequest;
import xcmg.device.infra.enums.GuaraenteesStatus;
import xcmg.device.infra.interceptor.externalApiCheck.handle.ApiCheckStrategy.ApiCheckOptionEnum;
import xcmg.device.service.ExternalParamCheckService;
import xcmg.device.service.company.CompanyInfoService;
import xcmg.device.service.crm.util.ActionResultUtil;
import xcmg.device.service.threeGuaranteesPur.ThreeGuaranteesOutService;
import xcmg.device.service.threeGuaranteesPur.ThreeGuaranteesPurService;
import xcmg.device.service.vo.ExternalParamCheckVO;
import xcmg.device.service.vo.FunctionResult;
import xcmg.device.service.vo.threeGuaranteesPur.CyThreeGuaranteesPurAddRespVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesOutVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurAddVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurAllDetailVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurDetailQueryVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurDetailVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurJCAddVO;
import xcmg.device.service.vo.threeGuaranteesPur.ThreeGuaranteesPurVO;
import xcmg.device.service.vo.threeGuaranteesPur.TjThreeGuaranteesPurAddRespVO;
import xcmg.device.service.vo.warehouse.FindMaterialsInfos;
import xcmg.device.service.vo.warehouse.FindMaterialsNumParam;
import xcmg.device.service.warehouse.WarehouseInventoryService;
import xcmg.device.service.warehouse.allot.RegionAllotService;
import yb.ecp.fast.infra.annotation.FastMappingInfo;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/threeGuaranteesPur")
public class ThreeGuaranteesPurController extends BasicController{
    @Autowired
    private ThreeGuaranteesPurService threeGuaranteesPurService;

    @Autowired
    private ExternalParamCheckService externalParamCheckService;

    @Autowired
    private WarehouseInventoryService warehouseInventoryService;
    @Autowired
    private RegionAllotService regionAllotService;

    @Autowired
    private ThreeGuaranteesOutService threeGuaranteesOutService;

    @Autowired
    private CompanyInfoMapper companyInfoMapper;
    @Autowired
    private CompanyInfoService companyInfoService;

    @RequestMapping(value = "/add",method = RequestMethod.POST)
    @ApiOperation(value = "增加三包采购申请")
    @FastMappingInfo(needLogin = true)
    public ActionResult add (@RequestBody ThreeGuaranteesPurAddVO threeGuaranteesPurAddVO)throws Exception {
        if(threeGuaranteesPurAddVO == null ){
            return actionResult(ErrorCode.IllegalArument);
        }

        threeGuaranteesPurAddVO.getHeaderInfo().setApplicationId(getUserId());
        threeGuaranteesPurAddVO.getHeaderInfo().setApplicationName(getUserName());
        threeGuaranteesPurAddVO.getHeaderInfo().setGuaraenteesStatus(GuaraenteesStatus.Saved.toString());
        ErrorCode ret=ErrorCode.Success;
        if(!StringUtils.isEmpty(threeGuaranteesPurAddVO.getHeaderInfo().getPurchaseNo())){
            ret=threeGuaranteesPurService.update(threeGuaranteesPurAddVO);
        }
        else {
            ret=threeGuaranteesPurService.add(threeGuaranteesPurAddVO, getOrgId());
        }
        return actionResult(ret);
    }

    @RequestMapping(value = "/submit",method = RequestMethod.POST)
    @FastMappingInfo(needLogin = true)
    public ActionResult submit(@RequestBody ThreeGuaranteesPurAddVO model)throws Exception{
        if(model==null){
            return actionResult(ErrorCode.IllegalArument);
        }
        model.getHeaderInfo().setGuaraenteesStatus(String.valueOf(GuaraenteesStatus.WaitAudit));
        model.getHeaderInfo().setApplicationId(getUserId());
        model.getHeaderInfo().setApplicationName(getUserName());
        ErrorCode ret=ErrorCode.Success;
        if(!StringUtils.isEmpty(model.getHeaderInfo().getPurchaseNo())){
            ret=threeGuaranteesPurService.update(model);
        }
        else {
            ret=threeGuaranteesPurService.add(model, getOrgId());
        }
        return actionResult(ret, model.getHeaderInfo().getId());
    }

    @RequestMapping(value = "/delete",method = RequestMethod.POST)
    @ApiOperation(value = "删除三包采购申请")
    @FastMappingInfo(needLogin = true,code = AuthCode.ThreeGuarantees.DEL)
    public ActionResult remove(@RequestBody String[] ids)throws Exception{
        if(ids==null||ids.length==0){
            return actionResult(ErrorCode.IllegalArument);
        }
        ErrorCode ret=threeGuaranteesPurService.remove(Arrays.asList(ids), getOrgId());
        return actionResult(ret);
    }

    @RequestMapping(value = "/update",method = RequestMethod.POST)
    @ApiOperation(value = "更新三包采购申请")
    @FastMappingInfo(needLogin = true)
    public ActionResult update(@RequestBody ThreeGuaranteesPurAddVO threeGuaranteesPurAddVO)throws Exception{
        if(threeGuaranteesPurAddVO.getHeaderInfo().getId() == null){
            return actionResult(ErrorCode.ThreePurchaseNo);
        }
        threeGuaranteesPurAddVO.getHeaderInfo().setGuaraenteesStatus("0");
        return actionResult(threeGuaranteesPurService.update(threeGuaranteesPurAddVO));
    }

    @RequestMapping(value = "/adjust",method = RequestMethod.POST)
    @ApiOperation(value = "调整三包采购申请")
    @FastMappingInfo(needLogin = true)
    public ActionResult adjust(@RequestBody ThreeGuaranteesPurAddVO threeGuaranteesPurAddVO)throws Exception{
        if(threeGuaranteesPurAddVO.getHeaderInfo().getId() == null){
            return actionResult(ErrorCode.ThreePurchaseNo);
        }
        return actionResult(threeGuaranteesPurService.adjust(threeGuaranteesPurAddVO));
    }

    @RequestMapping(value = "/list",method = RequestMethod.POST)
    @ApiOperation(value = "三包采购申请列表")
    @FastMappingInfo(needLogin = true)
    public ActionResult list(@RequestBody SearchCommonVO<ThreeGuaranteesPurVO> condition) throws Exception {
        ThreeGuaranteesPurVO threeGuaranteesPurVO=condition.getFilters();
        if(threeGuaranteesPurVO==null){
            threeGuaranteesPurVO=new ThreeGuaranteesPurVO();
        }
        threeGuaranteesPurVO.setOrgId(getOrgId());
        condition.setFilters(threeGuaranteesPurVO);
        PageCommonVO pageCommonVO=threeGuaranteesPurService.list(condition);
        return actionValueResult(pageCommonVO.getPageInfo());
    }


    @RequestMapping(value = "/listDetail",method = RequestMethod.POST)
    @ApiOperation(value = "三包采购申请明细列表")
    @FastMappingInfo(needLogin = true)
    public ActionResult<PageInfo<ThreeGuaranteesPurAllDetailVO>> listDetail(@RequestBody SearchCommonVO<ThreeGuaranteesPurDetailQueryVO> condition) throws Exception {
        ThreeGuaranteesPurDetailQueryVO threeGuaranteesPurVO=condition.getFilters();
        if(threeGuaranteesPurVO==null){
            threeGuaranteesPurVO=new ThreeGuaranteesPurDetailQueryVO();
        }
        threeGuaranteesPurVO.setOrgId(getOrgId());
        condition.setFilters(threeGuaranteesPurVO);
        PageCommonVO<ThreeGuaranteesPurAllDetailVO> pageCommonVO=threeGuaranteesPurService.listDetail(condition);
        return actionValueResult(pageCommonVO.getPageInfo());
    }

    @RequestMapping(value = "/item",method = RequestMethod.GET)
    @FastMappingInfo(needLogin = true)
    public ActionResult item(String id){
        if(StringUtils.isEmpty(id)){
            return actionResult(ErrorCode.IllegalArument);
        }
        return actionResult(ErrorCode.Success,threeGuaranteesPurService.item(id,null));
    }

    @RequestMapping(value = "/findDeliveryNum",method = RequestMethod.GET)
    @FastMappingInfo(needLogin = true)
    public ActionResult findByDeliveryNum(@RequestParam("id") String id,
                                          @RequestParam("warehouseCode") String warehouseCode)throws Exception{
        if(StringUtils.isEmpty(id) || StringUtils.isEmpty(warehouseCode)){
            return actionResult(ErrorCode.IllegalArument);
        }
        return actionResult(ErrorCode.Success,threeGuaranteesPurService.findDeliveryNum(id, warehouseCode, getOrgId()));
    }


    @RequestMapping(value = "/auditPass",method = RequestMethod.POST)
    @FastMappingInfo(needLogin = true,code = AuthCode.ThreeGuarantees.AUDIT)
    public ActionResult auditPass(@RequestBody ThreeGuaranteesPurVO threeGuaranteesPurVO) throws Exception{
        threeGuaranteesPurVO.setGuaraenteesStatus(GuaraenteesStatus.AuditPass.toString());
        threeGuaranteesPurVO.setRealAuditId(getUserId());
        threeGuaranteesPurVO.setAuditNote(threeGuaranteesPurVO.getAuditNote());
        return actionResult(threeGuaranteesPurService.auditBill(threeGuaranteesPurVO), threeGuaranteesPurVO.getId());
    }

    @RequestMapping(value = "/auditRefused",method = RequestMethod.POST)
    @FastMappingInfo(needLogin = true,code = AuthCode.ThreeGuarantees.AUDIT)
    public ActionResult auditRefused(@RequestBody ThreeGuaranteesPurVO threeGuaranteesPurVO) throws Exception{
        threeGuaranteesPurVO.setGuaraenteesStatus(GuaraenteesStatus.AuditRefused.toString());
        threeGuaranteesPurVO.setRealAuditId(getUserId());
        threeGuaranteesPurVO.setAuditNote(threeGuaranteesPurVO.getAuditNote());
        return actionResult(threeGuaranteesPurService.auditBill(threeGuaranteesPurVO));
    }

    //导出
    @RequestMapping(value = "/export",method = RequestMethod.POST)
    @FastMappingInfo(needLogin = true,code = AuthCode.ThreeGuarantees.EXPORT)
    public void export(String[] ids,String warehouseCode)throws Exception {
//        threeGuaranteesPurService.export(Arrays.asList(ids),warehouseCode);
        threeGuaranteesPurService.exportV2(Arrays.asList(ids),warehouseCode);
    }

    @RequestMapping(value = "/exportAll",method = RequestMethod.POST)
    @FastMappingInfo(needLogin = true,code = AuthCode.ThreeGuarantees.EXPORT)
    public void exportAll(ThreeGuaranteesPurVO condition)throws Exception {
        if(condition == null){
            condition = new ThreeGuaranteesPurVO();
        }
        condition.setOrgId(getOrgId());
        threeGuaranteesPurService.exportAllV2(condition);
    }

    @ResponseBody
    @RequestMapping(value = "/import", method = RequestMethod.POST)
    @FastMappingInfo(needLogin = true)
    public ActionResult importExcel(HttpServletRequest request) throws Exception{
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        MultipartFile file = multipartRequest.getFile( multipartRequest.getFileNames().next());
        String fileName = file.getOriginalFilename();
        FunctionResult<String> result=new FunctionResult<>();
        if (!fileName.trim().endsWith(".xls")) {
            result.setCode(ErrorCode.ImportExcelEndWithXLS);
        } else {
            InputStream in = file.getInputStream();
            result= threeGuaranteesPurService.importExcel(in,  getOrgId());
        }
        return actionResult(result.getCode(), result.getValue());
    }

    @RequestMapping(value = "/download",method = RequestMethod.POST)
    @FastMappingInfo(needLogin = true)
    public void download() throws Exception {
        threeGuaranteesPurService.download();
    }

    /**
     * 对外提供添加接口
     *
     * @param model
     * @return
     * @throws Exception
     */
//    @RequestMapping(value = "/addThreeGuaranteesPur", method = RequestMethod.POST)
//    //@FastMappingInfo(needLogin = true)
//    public ActionResult addThreeGuaranteesPur(@RequestBody ThreeGuaranteesPurAddVO model) throws Exception {
//        log.info("addThreeGuaranteesPur接口入参：{}",model);
//        ThreeGuaranteesPurVO headerInfo = model.getHeaderInfo();
//        String sapCode = headerInfo.getSapCode();
//        log.info("addThreeGuaranteesPur抛单，sapCode为{}",sapCode);
//        //随车需要自动创建出库单
//        if(CompanyUtil.isSCSapCode(sapCode)){
//            try {
//                log.info("addThreeGuaranteesPur抛单，随车请求处理");
//                return threeGuaranteesPurService.synSCThreeGuarantees(model);
//            } catch (Exception e) {
//                return actionResult(ErrorCode.Failure,e.getMessage(), e.getMessage());
//            }
//        }else{
//            return doAddThreeGuaranteesPur(model);
//        }
//    }

    /**
     * @Des 基础三包申请单抛单
     * 校验规则见ApiCheckOption1Service中注释
     * @Date 2021/5/27 20:53
     * @Author wangzhaoyu
     * @Param [model]
     * @Return yb.ecp.fast.infra.infra.ActionResult
     */
    @RequestMapping(value = "/addJC", method = RequestMethod.POST)
    @ExternalApiRequest(ApiCheckOptionEnum.OPTION_SECRET)
    public ActionResult addThreeGuaranteesJC(@RequestBody ThreeGuaranteesPurJCAddVO model) throws Exception {
        log.info("基础吊用三包单抛单接口入参:{}",model);
        threeGuaranteesPurService.synJCThreeGuarantees(model);
        log.info("基础吊用三包单抛单接口:{}",model);
        return ActionResultUtil.successActionResult();
    }


    /**
     * 对外提供添加接口，需要验证，对外部新接入的调用请使用此接口
     * 校验规则见ApiCheckOption1Service中注释
     *
     * @param model
     * @return
     * @throws Exception
     */
//    @RequestMapping(value = "/addThreeGuaranteesPurBySec", method = RequestMethod.POST)
//    @ExternalApiRequest(ApiCheckOptionEnum.OPTION_SECRET)
//    public ActionResult addThreeGuaranteesPurBySec(@RequestBody ThreeGuaranteesPurAddVO model) throws Exception {
//        log.info("addThreeGuaranteesPurBySec接口入参：{}",model);
//        ThreeGuaranteesPurVO headerInfo = model.getHeaderInfo();
//        String sapCode = headerInfo.getSapCode();
//        log.info("addThreeGuaranteesPurBySec抛单，sapCode为{}",sapCode);
//        //随车需要自动创建出库单
//        if(CompanyUtil.isSCSapCode(sapCode)){
//            try {
//                log.info("addThreeGuaranteesPurBySec抛单，随车请求处理");
//                return threeGuaranteesPurService.synSCThreeGuarantees(model);
//            } catch (Exception e) {
//                return actionResult(ErrorCode.Failure,e.getMessage(), e.getMessage());
//            }
//        }else{
//            return doAddThreeGuaranteesPur(model);
//        }
//    }
    private ActionResult doAddThreeGuaranteesPur(ThreeGuaranteesPurAddVO model) {
        if (null == model || null == model.getHeaderInfo() || model.getDetailList().isEmpty()) {
            return actionResult(ErrorCode.IllegalArument);
        }
        ThreeGuaranteesPurVO headerInfo = model.getHeaderInfo();
        String sapCode = headerInfo.getSapCode();
        CompanyInfoDO companyInfo = companyInfoService.getBySapCode(sapCode);
        if (companyInfo == null) {
            return ActionResultUtil.actionResult(ErrorCode.Failure.getCode(), ErrorCode.Failure.getDesc(),"sapCode不存在");
        }
        ActionResult result;
        try {
            externalParamCheckService.checkParam(fillNeedCheckParan(model));
            result = threeGuaranteesPurService.addThreeGuaranteesPur(model,companyInfo);
        } catch (Exception e) {
            return actionResult(ErrorCode.Failure,e.getMessage(), e.getMessage());
        }
        return result;
    }

    private ExternalParamCheckVO fillNeedCheckParan(ThreeGuaranteesPurAddVO model) throws Exception {
        ExternalParamCheckVO param = new  ExternalParamCheckVO();
        if (CollectionUtils.isEmpty(model.getDetailList())) {
            throw new Exception("缺少零件信息");
        }
        List<String> materialsNos = new ArrayList<>();
        for (ThreeGuaranteesPurDetailVO detailVO : model.getDetailList()) {
            materialsNos.add(detailVO.getMaterialsNo());
        }
        param.setMaterialsNos(materialsNos);
        param.setSapCode(model.getHeaderInfo().getSapCode());
        param.setDeliveryTypeId(model.getHeaderInfo().getDeliveryTypeId());
        param.setSettleTypeId(model.getHeaderInfo().getSettleTypeId());
        return param;
    }

    /**
     * 对外提供添加接口，需要验证，对外部新接入的调用请使用此接口
     * 校验规则见ApiCheckOption1Service中注释
     *
     * @param model
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/add4Tj", method = RequestMethod.POST)
    @ExternalApiRequest(ApiCheckOptionEnum.OPTION_SECRET)
    public ActionResult add4Tj(@RequestBody ThreeGuaranteesPurAddVO model) throws Exception {
        log.info("addThreeGuaranteesPur接口入参：【{}】" , model);
        TjThreeGuaranteesPurAddRespVO respBody = new TjThreeGuaranteesPurAddRespVO();
        ThreeGuaranteesPurVO purVO = model.getHeaderInfo();
        String orgId = companyInfoMapper.getOrgIdBySapCode(purVO.getSapCode());
        //默认参数拼接
        defalutPurParamAssemble(model,orgId);
        //参数合法性校验
        ActionResult tjParamCheck = model.tjParamCheck();
        if(!successActionResult(tjParamCheck)){
            return tjParamCheck;
        }

        //crmOrder重复单号校验
        ActionResult crmOrderDulpCheck = crmOrderDulpCheck(model);
        if(crmOrderDulpCheck != null && successActionResult(crmOrderDulpCheck)){
            return crmOrderDulpCheck;
        }

        // 赋值出库仓库编码，出库仓库名称取serviceSite+'备件库'，通过名称匹配仓库编码
        String outLocation = assembleOutLocation(orgId,purVO.getServiceSite());
        //校验库存，出库之前就要校验库存，不做出库拦截，只是要返回给CRM做个提示，要放在出库操作之前做校验，不然统计出来的当前库存就不准了
        boolean haveInvatory = checkWareHouseInvatory(model, orgId, outLocation);
        //202200919-胡彬需求，因为crm传过来的零件明细中存在多条materialSNo相同但是barcode不同的数据，这种数据系统不支持，需要进行手动合并
        materialsGroupMerge(model);
        try{
            //生成三包申请和三包出库单
            ThreeGuaranteesOutDO threeGuaranteesOutDO = threeGuaranteesOutService.synServiceTicket4Tj(model, outLocation, orgId);
            String guaranteesOutNo = threeGuaranteesOutDO.getGuaranteesOutNo();
            ActionResult result = new ActionResult(ErrorCode.Success.getCode());
            //返回三包出库单的单号
            respBody.setValue(guaranteesOutNo);
            if(haveInvatory){
                respBody.setCheckCode(0);
                respBody.setCheckMessage("");
            }else{
                respBody.setCheckCode(1);
                respBody.setCheckMessage("PMS库存不足");
            }
            result.setValue(respBody);
            return result;
        }catch (Exception e){
            LogHelper.monitor("同步服务单异常>>>"+e.getMessage());
            ActionResult result = new ActionResult(ErrorCode.Failure.getCode(),"同步服务单失败:"+e.getMessage());
            respBody.setCheckCode(0);
            respBody.setCheckMessage("");
            result.setValue(respBody);
            return result;
        }
    }

    /**
    *@Description 202200919-胡彬需求，因为crm传过来的零件明细中存在多条materialSNo相同但是barcode不同的数据，这种数据系统不支持，需要进行手动合并
    *@Author wzy
    *@Date 2020/9/19
    *@Time 9:50
    */
    private void materialsGroupMerge(ThreeGuaranteesPurAddVO model) {
        List<ThreeGuaranteesPurDetailVO> detailList = model.getDetailList();
        //*******处理之前先把原始的零件信息记录下来
        writeTJOriginalDetail(model);
        LogHelper.monitor("塔机请求同步服务单接口合并前零件详情为>>"+ JsonUtil.objectToString(detailList));
        Map<String,ThreeGuaranteesPurDetailVO> groupMap = new HashMap<>();
        for(ThreeGuaranteesPurDetailVO purDetailVO : detailList){
            String materialsNo = purDetailVO.getMaterialsNo();
            ThreeGuaranteesPurDetailVO cacheDetail = groupMap.get(materialsNo);
            if(cacheDetail == null){
                groupMap.put(materialsNo,purDetailVO);
            }else{
                //如果已经存在了，则需要把原来的数据取出来，零件数量相加,然后清空barcod信息
                BigDecimal purchaseQty = cacheDetail.getPurchaseQty() == null ? BigDecimal.ZERO : cacheDetail.getPurchaseQty();
                BigDecimal curerntDetailPurchaseQty = purDetailVO.getPurchaseQty() == null ? BigDecimal.ZERO : purDetailVO.getPurchaseQty();
                purchaseQty = purchaseQty.add(curerntDetailPurchaseQty);
                cacheDetail.setPurchaseQty(purchaseQty);
                cacheDetail.setBarcode(null);
            }
        }
        List<ThreeGuaranteesPurDetailVO> result = new ArrayList<>(groupMap.values());
        LogHelper.monitor("塔机请求同步服务单接口合并后零件详情为》》》》》"+ JsonUtil.objectToString(detailList));
        model.setDetailList(result);
    }

    private void writeTJOriginalDetail(ThreeGuaranteesPurAddVO model){
        List<ThreeGuaranteesPurDetailVO> originalDetails = new ArrayList<>();
        List<ThreeGuaranteesPurDetailVO> detailList = model.getDetailList();
        for(ThreeGuaranteesPurDetailVO detailVO : detailList){
            ThreeGuaranteesPurDetailVO originalDetail = new ThreeGuaranteesPurDetailVO();
            BeanUtils.copyProperties(detailVO,originalDetail);
            originalDetails.add(originalDetail);
        }
        model.setOriginDetailList(originalDetails);
    }


    /**判断crmOrder是否已经存在记录，如果存在则返回操作成功，同时返回存在的PMS编号--
     这么返回的原因crm调接口大多加在签核流程里面，多次点击触发接口，返回已存在，会影响签核的动作（具体可以问瑞泰-黄远辉）
     返回null代表流程可以继续往下走，返回code=0或者不为0的时候流程都不往下走*/
    private ActionResult crmOrderDulpCheck(ThreeGuaranteesPurAddVO model) {
        TjThreeGuaranteesPurAddRespVO respBody = new TjThreeGuaranteesPurAddRespVO();
        String crmOrder = model.getHeaderInfo().getCrmOrder();
        if(StringUtils.isEmpty(crmOrder)){
            return actionResult(ErrorCode.Failure,"crm订单号不能为空",respBody);
        }
        List<ThreeGuaranteesPurDO> purs = threeGuaranteesPurService.getPurByCrmOrder(crmOrder);
        if(!CollectionUtils.isEmpty(purs)){
            respBody.setCheckCode(0);
            respBody.setCheckMessage("");
            ThreeGuaranteesPurDO threeGuaranteesPurDO = purs.get(0);
            String purchaseNo = threeGuaranteesPurDO.getPurchaseNo();
            // 返回出库单编码
            List<ThreeGuaranteesOutDO> outs = threeGuaranteesOutService.findOutsByPurchaseNo(purchaseNo);
            String outNo = CollectionUtils.isEmpty(outs) ? "" : outs.get(0).getGuaranteesOutNo();
            respBody.setValue(outNo);
            return actionResult(ErrorCode.Success,"CRM单号已存在",respBody);
        }
        return null;
    }

    //塔机的请求涩会给你成出库单设置默认的参数
    private void defaultOutParamAssemble(ThreeGuaranteesPurDO purDO,ThreeGuaranteesOutVO outVo,String orgId,String outLocation){
        outVo.setOutArea(outLocation);
        outVo.setSapOutArea(outLocation);

        String customerId = purDO.getCustomerId();
        String customerName = purDO.getCustomerName();
        if(!StringUtils.isEmpty(customerId)){
            outVo.setPurchaseOrgId(customerId);
        }
        if(StringUtils.isEmpty(customerName)){
            outVo.setPurchaseOrgName(customerName);
        }
        outVo.setCreatePartId("455404133906644992");
        outVo.setCreatePartName("服务部");
        outVo.setCreateId("455404133906644992");
        outVo.setCreateName("接口用户");
        outVo.setOutLocation(outLocation);
    }

    //塔机的请求生成申请单设置默认的参数
    private void defalutPurParamAssemble(ThreeGuaranteesPurAddVO model,String orgId) {
        ThreeGuaranteesPurVO headerInfo = model.getHeaderInfo();
        String guaraenteesStatus = headerInfo.getGuaraenteesStatus() == null ? "2" : headerInfo.getGuaraenteesStatus();
        String statusDesc = headerInfo.getStatusDesc() == null ? "审核通过" : headerInfo.getStatusDesc();
        String customerSapCode = headerInfo.getCustomerSapCode();
        if(!StringUtils.isEmpty(customerSapCode)){
            CompanyDealerDO companyDealer = threeGuaranteesPurService.getCompanyDealer(orgId, customerSapCode);
            if(companyDealer != null){
                String dealerOrgId = companyDealer.getDealerOrgId();
                String companyName = companyDealer.getCompanyName();
                headerInfo.setCustomerId(dealerOrgId);
                headerInfo.setCustomerName(companyName);
            }
        }
        headerInfo.setGuaraenteesStatus(guaraenteesStatus);
        headerInfo.setStatusDesc(statusDesc);
        headerInfo.setDispatcherId("477477706045325312");
        headerInfo.setDispatcherName("接口用户");
        headerInfo.setRealAuditId("477477706045325312");
        headerInfo.setRealAuditName("接口用户");
        headerInfo.setRealAuditDate(new Date());
    }

    /**
     * 赋值出库仓库编码，出库仓库名称取serviceSite+'备件库'，通过名称匹配仓库编码
     * @param serviceSite
     * @return
     */
    private String assembleOutLocation(String orgId,String serviceSite) throws Exception {
        if(StringUtils.isEmpty(serviceSite)){
            return null;
        }
        String outWareHouse = serviceSite + "备件库";
        List<WarehouseDO> inwarehouse = regionAllotService.getWareHousesByOrgAndDescription(orgId, outWareHouse);
        if(inwarehouse.size() < 1){
            return null;
        }
        return inwarehouse.get(0).getWarehouseCode();
    }

    /**
     * 库存校验
     * @param model
     * @param orgId
     * @param outLocation
     * @return
     */
    private boolean checkWareHouseInvatory(ThreeGuaranteesPurAddVO model,String orgId,String outLocation){
        try{
            List<FindMaterialsInfos> infos=new ArrayList<>();
            for (ThreeGuaranteesPurDetailVO detailVO : model.getDetailList()) {
                FindMaterialsInfos findMaterialsInfos=new FindMaterialsInfos();
                findMaterialsInfos.setMaterialsNo(detailVO.getMaterialsNo());
                findMaterialsInfos.setAmount(detailVO.getPurchaseQty());
                infos.add(findMaterialsInfos);
            }
            FindMaterialsNumParam findMaterialsNumParam=new FindMaterialsNumParam();
            findMaterialsNumParam.setMaterialsNos(infos);
            findMaterialsNumParam.setOrgId(orgId);
            findMaterialsNumParam.setWarehousCode(outLocation);
            return warehouseInventoryService.tjFindMaterialsNum(findMaterialsNumParam);
        }catch (Exception e){
            LogHelper.error("来自塔机的三包申请创建三包校验库存出现异常，" + e.getMessage(), ErrorCode.Failure.getCode());
            return true;
        }
    }

    /**
     * 对外提供添加接口，需要验证（铲运）
     * 校验规则见ApiCheckOption1Service中注释
     *
     * @param model
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/add4Cy", method = RequestMethod.POST)
    @ApiOperation(value = "三包采购申请(铲运)")
    @ExternalApiRequest(ApiCheckOptionEnum.OPTION_SECRET)
    public ActionResult add4Cy(@RequestBody ThreeGuaranteesPurAddVO model) throws Exception {
        log.info("addThreeGuaranteesPur接口入参：【{}】" , model);
        CyThreeGuaranteesPurAddRespVO respBody = new CyThreeGuaranteesPurAddRespVO();
        ThreeGuaranteesPurVO purVO = model.getHeaderInfo();
        String orgId = companyInfoMapper.getOrgIdBySapCode(purVO.getSapCode());
        //铲运默认参数拼接
        defalutCyPurParamAssemble(model,orgId);
        //参数合法性校验
        ActionResult cyParamCheck = model.cyParamCheck();
        if(!successActionResult(cyParamCheck)){
            return cyParamCheck;
        }

        //crmOrder重复单号校验
        ActionResult crmOrderDulpCheck = crmOrderDulpCheck(model);
        if(crmOrderDulpCheck != null && successActionResult(crmOrderDulpCheck)){
            return crmOrderDulpCheck;
        }

        // 赋值出库仓库编码，出库仓库名称取serviceSite+'备件库'，通过名称匹配仓库编码
        String outLocation = assembleOutLocation(orgId,purVO.getServiceSite());
        //校验库存，出库之前就要校验库存，不做出库拦截，只是要返回给CRM做个提示，要放在出库操作之前做校验，不然统计出来的当前库存就不准了
        boolean haveInventory = checkCyWarehouseInventory(model, orgId, outLocation);
        //零件明细中存在多条materialsNo相同但是barcode不同的数据，需要进行手动合并
        materialsGroupCyMerge(model);
        try{
            //生成三包申请和三包出库单
            ThreeGuaranteesOutDO threeGuaranteesOutDO = threeGuaranteesOutService.synServiceTicket4Cy(model, outLocation, orgId);
            String guaranteesOutNo = threeGuaranteesOutDO.getGuaranteesOutNo();
            ActionResult result = new ActionResult(ErrorCode.Success.getCode());
            //返回三包出库单的单号
            respBody.setValue(guaranteesOutNo);
            if(haveInventory){
                respBody.setCheckCode(0);
                respBody.setCheckMessage("");
            }else{
                respBody.setCheckCode(1);
                respBody.setCheckMessage("PMS库存不足");
            }
            result.setValue(respBody);
            return result;
        }catch (Exception e){
            LogHelper.monitor("同步服务单异常>>>"+e.getMessage());
            ActionResult result = new ActionResult(ErrorCode.Failure.getCode(),"同步服务单失败:"+e.getMessage());
            respBody.setCheckCode(0);
            respBody.setCheckMessage("");
            result.setValue(respBody);
            return result;
        }
    }

    @RequestMapping(value = "/revert", method = RequestMethod.GET)
    @ApiOperation(value = "撤销")
    public ActionResult revert(String id) throws Exception {
        return actionResult(threeGuaranteesOutService.revert(id));
    }

    /**
     * 铲运的请求生成申请单设置默认的参数
     * @param model
     * @param orgId
     */
    private void defalutCyPurParamAssemble(ThreeGuaranteesPurAddVO model,String orgId) {
        ThreeGuaranteesPurVO headerInfo = model.getHeaderInfo();
        String guaraenteesStatus = headerInfo.getGuaraenteesStatus() == null ? "2" : headerInfo.getGuaraenteesStatus();
        String statusDesc = headerInfo.getStatusDesc() == null ? "审核通过" : headerInfo.getStatusDesc();
        String customerSapCode = headerInfo.getCustomerSapCode();
        if(!StringUtils.isEmpty(customerSapCode)){
            CompanyDealerDO companyDealer = threeGuaranteesPurService.getCompanyDealer(orgId, customerSapCode);
            if(companyDealer != null){
                String dealerOrgId = companyDealer.getDealerOrgId();
                String companyName = companyDealer.getCompanyName();
                headerInfo.setCustomerId(dealerOrgId);
                headerInfo.setCustomerName(companyName);
            }
        }
        headerInfo.setGuaraenteesStatus(guaraenteesStatus);
        headerInfo.setStatusDesc(statusDesc);
        headerInfo.setDispatcherId("477477706045325312");
        headerInfo.setDispatcherName("铲运接口用户");
        headerInfo.setRealAuditId("477477706045325312");
        headerInfo.setRealAuditName("铲运接口用户");
        headerInfo.setRealAuditDate(new Date());
    }

    /**
     * 库存校验（铲运）
     * @param model
     * @param orgId
     * @param outLocation
     * @return
     */
    private boolean checkCyWarehouseInventory(ThreeGuaranteesPurAddVO model,String orgId,String outLocation){
        try{
            List<FindMaterialsInfos> infos = new ArrayList<>();
            FindMaterialsInfos findMaterialsInfos;
            for (ThreeGuaranteesPurDetailVO detailVO : model.getDetailList()) {
                findMaterialsInfos = new FindMaterialsInfos();
                findMaterialsInfos.setMaterialsNo(detailVO.getMaterialsNo());
                findMaterialsInfos.setAmount(detailVO.getPurchaseQty());
                infos.add(findMaterialsInfos);
            }
            FindMaterialsNumParam findMaterialsNumParam=new FindMaterialsNumParam();
            findMaterialsNumParam.setMaterialsNos(infos);
            findMaterialsNumParam.setOrgId(orgId);
            findMaterialsNumParam.setWarehousCode(outLocation);
            return warehouseInventoryService.cyFindMaterialsNum(findMaterialsNumParam);
        }catch (Exception e){
            LogHelper.error("来自铲运的三包申请创建三包出库单校验库存出现异常，" + e.getMessage(), ErrorCode.Failure.getCode());
            return true;
        }
    }

    /**
    * @Desc   进行手动合并条码
    * @Author Mr.dong
    * @Date   2020/12/15 18:12
    */
    private void materialsGroupCyMerge(ThreeGuaranteesPurAddVO model) {
        List<ThreeGuaranteesPurDetailVO> detailList = model.getDetailList();
        //处理之前先把原始的零件信息记录下来
        writeCyOriginalDetail(model);
        LogHelper.monitor("铲运请求同步服务单接口合并前零件详情为>>"+ JsonUtil.objectToString(detailList));
        Map<String,ThreeGuaranteesPurDetailVO> groupMap = new HashMap<>();
        for(ThreeGuaranteesPurDetailVO purDetailVO : detailList){
            String materialsNo = purDetailVO.getMaterialsNo();
            ThreeGuaranteesPurDetailVO cacheDetail = groupMap.get(materialsNo);
            if(cacheDetail == null){
                groupMap.put(materialsNo,purDetailVO);
            }else{
                //如果已经存在了，则需要把原来的数据取出来，零件数量相加,然后清空barcode信息
                BigDecimal purchaseQty = cacheDetail.getPurchaseQty() == null ? BigDecimal.ZERO : cacheDetail.getPurchaseQty();
                BigDecimal curerntDetailPurchaseQty = purDetailVO.getPurchaseQty() == null ? BigDecimal.ZERO : purDetailVO.getPurchaseQty();
                purchaseQty = purchaseQty.add(curerntDetailPurchaseQty);
                cacheDetail.setPurchaseQty(purchaseQty);
                cacheDetail.setBarcode(null);
            }
        }
        List<ThreeGuaranteesPurDetailVO> result = new ArrayList<>(groupMap.values());
        LogHelper.monitor("铲运请求同步服务单接口合并后零件详情为》》》》》"+ JsonUtil.objectToString(detailList));
        model.setDetailList(result);
    }

    private void writeCyOriginalDetail(ThreeGuaranteesPurAddVO model){
        List<ThreeGuaranteesPurDetailVO> originalDetails = new ArrayList<>();
        List<ThreeGuaranteesPurDetailVO> detailList = model.getDetailList();
        ThreeGuaranteesPurDetailVO originalDetail;
        for(ThreeGuaranteesPurDetailVO detailVO : detailList){
            originalDetail = new ThreeGuaranteesPurDetailVO();
            BeanUtils.copyProperties(detailVO,originalDetail);
            originalDetails.add(originalDetail);
        }
        model.setOriginDetailList(originalDetails);
    }

}
